Welcome to EOELAB!
EOELAB 架构决策记录
EOELAB 架构决策记录
本文档记录 EOELAB 互联云关键设计决策、做出这些决策的原因,以及被放弃的主要替代方案。
阅读导览
- 为什么不用 Kubernetes → ADR-0001
- 存储保护策略如何选 → ADR-0002
- 存储底座如何选 → ADR-0003
- 网络基础设施如何选 → ADR-0004
- 联邦网络为什么用 Headscale/Tailscale → ADR-0005
- Runner 为什么默认用 lxc 而非 vm / 为什么拒绝 dind → ADR-0006
ADR-0001:选择 Incus 而不是 Kubernetes
状态:Accepted
决策:EOELAB 的本地域以 Incus 为基础运行 vm/lxc/oci 同层调度,不基于 Kubernetes 构建本地控制平面。
背景:Kubernetes 深刻定义了云计算时代,但它背后的若干隐含前提在现实中并不总是成立。当这些前提缺失时,K8S 模型会暴露出一些值得警惕的局限性。
被放弃方案:Kubernetes
- 规模不匹配:K8S 的设计起点是 Google 级别的集群规模,而绝大多数团队并不面对前 1‰ 的极端场景。在没有同等专业运维能力的前提下,强行采用 K8S 往往导致维护成本远超收益,形成“过度工程”。
- 网络可达性:头部企业拥有充裕的公网 IP 与稳定的 BGP 互联,但更多场景中,设备位于多层 NAT 之后,公网资源匮乏。K8S 默认的节点直连与 LoadBalancer 模型在这些环境中难以直接工作,需要大量额外适配。
- 安全配置门槛:RBAC、NetworkPolicy、PodSecurityPolicy 等机制虽然强大,但配置复杂、易出错。在缺乏专职安全团队与审计流程的情况下,默认配置往往暴露出比传统部署更多的攻击面,误操作与恶意利用的风险不可忽略。
- 高性能硬件的自限性:RoCE/InfiniBand 等高性能网络,以及 NVMe over Fabrics 等存储技术,都有物理拓扑和距离带来的性能边界。K8S 将一切抽象为可调度资源,容易掩盖跨机架、跨数据中心访问时的延迟与带宽衰减。“跨数据中心共享”在实际性能上往往是不成立的。
- 数据主权风险:控制平面掌握全局元数据,etcd 存储集群全部状态。任何获得 API 访问权限的实体都可能枚举甚至导出敏感信息。在数据主权日益受到重视的背景下,这种集中化模型天然加大了数据泄露和监管合规的风险。
- 抽象层堆叠:CRD、Operator、Sidecar、Service Mesh……生态持续叠加抽象层次。每一层抽象都带来新的概念负担和故障模式。最终,运维人员可能花费大量精力去维护抽象本身,而不是解决业务问题。
- 控制平面中心化:即便 etcd 和 API Server 以高可用形式部署,K8S 仍然要求所有节点、所有操作向逻辑上的单一控制平面汇报。这种“决策集中、执行分布”的模型,与边缘自治、离线容忍、局部自愈等需求存在天然冲突。在一个宣称分布式的系统中,控制平面的单点逻辑依然是一个根本性约束。
选择 Incus 的理由:
- 承认计算资源的“地域性”与“主权性”,每个本地域拥有独立控制面
- 支持 vm/lxc/oci 同层调度,无需复杂的 Pod/CRD 抽象即可满足多数需求
- 更适应多层 NAT、小规模和边缘场景,降低运维门槛
- 本地域自负责,避免全局控制平面带来的数据主权风险
后果:需要自行解决联邦层面的权限、网络和镜像协作,因此引入联邦设施作为补充。
ADR-0002:存储保护策略选择
状态:Accepted
决策:热数据强制使用多副本;温/冷数据根据底座选择 RAID-Z(TrueNAS)或纠删码(EC,Ceph)。
背景:不同温度数据在访问频率、延迟敏感度、容量效率之间存在显著差异,需要匹配不同的冗余机制。
被放弃或受限方案:
- 传统 RAID5/6:存在写漏洞,重建期间性能极差且第二块盘故障风险高;对大容量磁盘(>2TB)重建时间过长,因此只采用 RAID-Z。
- 分层缓存(L2ARC/SLOG):TrueNAS 和 Ceph 的缓存机制会带来不可控的性能波动并扩大故障面;Ceph 共享 SSD 作为多个 OSD 元数据设备时,SSD 失效可能引发批量 OSD down 及 PG 大规模降级。因此遵循“显式配置优于缓存”原则,将相同介质与性能等级的磁盘组池而不使用分层缓存。
选择理由:
- 多副本:读写性能高,随机写友好,故障恢复快,适合热数据
- RAID-Z:存储利用率高,适合写入频率低、对延迟不敏感的温/冷数据
- EC:在 Ceph 中平衡存储效率与可靠性,适合多节点/大文件场景
后果:
- 热数据最小副本数:Btrfs/TrueNAS 为 2,Ceph 为 3
- 温/冷数据 TrueNAS 优先 Z2,Ceph 温数据 4+2、冷数据 8+3 或更高
- 磁盘极少时(每节点 1–2 盘)使用多副本,避免 EC 小文件放大
ADR-0003:存储底座选择
状态:Accepted
决策:本地存储用 Btrfs;小/中规模共享存储(3–6 节点)用 TrueNAS;大/超大规模(≥7 节点)用 Ceph。不支持 LINSTOR,不支持 TrueNAS 双机。
背景:需要覆盖单机、中小规模集群、大规模集群三种场景,并在接口、性能、运维复杂度之间取得平衡。
被放弃方案:
- LINSTOR:不支持实例间共享自定义卷、不支持在多个节点之间共享同一 LINSTOR 资源组、不支持从旧快照恢复,因此不纳入支持范围。
- TrueNAS 双机:双机 HA 模式需要企业级订阅;现代单机存储服务器性能足够支持中规模存储;无订阅配置为两台独立 TrueNAS 只会增加运维复杂度。
- Ceph 用于小/中规模:Ceph 的运维复杂度、EC 小文件放大等成本在小规模场景下不划算。
选择理由:
- Btrfs:适合本地文件系统接口,简单直接
- TrueNAS:单机/小中规模下 RAID/RAID-Z 性能理想,无需企业级订阅即可使用
- Ceph:大/超大规模下具备 EC、多接口、横向扩展能力,EC 4+2 起步即可满足基本节点级容错
后果:
- 存储接口命名需统一为
<接口类型>_<介质><容量><性能> 格式 - 集群必须保证各节点数据接口一致
- 多节点场景优先计算与存储分离
ADR-0004:网络基础设施选择
状态:Accepted
决策:本地域物理网络建立在以太网结构上;1/2.5G 使用电口;10G 及以上使用光口 + RoCEv2;不使用 InfiniBand;网关使用硬件路由器/防火墙;虚拟网络单节点用 bridge、集群用 ovn。
背景:需要同时满足普通业务、存储、HPC/GPU 通信等多种带宽与延迟需求,并控制成本和运维复杂度。
被放弃方案:
- InfiniBand:虽然性能优异,但 EOELAB 建立在以太网结构上,不考虑使用 InfiniBand。
- 10G 电口:10G RJ45 网卡发热严重且不利于后续网络升级,因此不推荐。
- 软定义网关/防火墙:出于稳定性和可维护性考虑,本地域网关使用硬件路由器/防火墙,不使用软定义网络设备。
选择理由:
- 1/2.5G:电口成本低,无需 RDMA,适合标准业务与小规模存储
- 10G:光口(SFP+ + DAC)+ RoCEv2 在成本与性能间取得平衡,适合中规模存储
- ≥40G:强制 RoCEv2,避免高带宽网络造成 CPU 解包高负载,适合大/超大规模存储与轻量 HPC/GPU
- 单节点用 bridge 保证性能最佳;集群用 ovn 满足服务迁移与高可用
后果:
- 物理网络默认使用 DAC 线,无需光模块
- 使用 RoCEv2 需要支持 PFC 和 ECN 的交换机与网卡
- SR-IOV 仅在 GPU RDMA、特定 HPC 等高性能场景才考虑
ADR-0005:联邦网络方案选择
状态:Accepted
决策:联邦网络使用基于 Headscale 的 Tailscale/WireGuard MESH 网络,节点使用 CGNAT 网段,禁用 Headscale 内置 DERP,由社区部署独立 derper 中继节点。
背景:联邦需要让无公网 IP 的节点互相可达,同时保持零信任、最小暴露、可插拔的原则。
被放弃方案:
- 反向代理/隧道穿透工具:不得使用反向代理/隧道穿透工具将联邦网络内部端点映射到公网节点上暴露,以避免绕过安全边界和引入不稳定依赖。
- Headscale 内置 DERP:禁用内置服务器,改为由社区部署独立 derper 节点,以获得更好的地理覆盖和可控性。
选择理由:
- WireGuard 提供点对点加密隧道,标准通信无需额外加密
- MESH 模型允许任何节点直接互联,无需集中式转发
.eoelab 内部域名提供稳定的节点发现,不必担心 IP 漂移- 服务账户通过 ZITADEL 实现 mTLS 或 OAuth2 access token,满足端到端保护需求
后果:
- IPv4 使用 100.64.0.0/10,IPv6 使用 fd7a:115c:a1e0::/48
- 云服务器激活客户端可能导致内部镜像解析到 CGNAT 范围,需要换源到公网站点(如 USTC 镜像源)
- DERP 节点需要备案域名和公共 CA 证书(中国大陆云服务器)
ADR-0006:Runner 运行时策略
状态:Accepted
决策:通用 Runner 默认使用 lxc 容器,仅在需要特权内核时使用 vm;OCI 镜像构建使用 kaniko,镜像操作使用 crane,拒绝 dind 和 docker 操作 registry。
背景:Runner 需要兼顾隔离性、性能、安全性和 CI/CD 生态兼容性。
被放弃方案:
- Docker in Docker(dind):存在特权、复杂性和安全风险,拒绝使用。
- docker 操作 registry: crane 更轻量、更适合 CI 场景,因此拒绝 docker 操作 registry。
- 默认 vm:虽然功能完整,但资源开销更大,仅在确实需要特权内核时才使用。
选择理由:
- lxc 在多数构建场景下足够,且资源开销低于 vm
- kaniko 在非特权环境下完成 OCI 镜像构建,避免 dind
- crane 专注于镜像操作,适合 CI/CD 流水线
后果:
- tag 策略:
[size, arch, runtime],size 仅使用内存规模(tiny/small/medium) - 专用 runner 通过
[purpose] 标签处理特定任务(如 mirror) - 节点预装
git